﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using Microsoft.CSharp;
using System.CodeDom.Compiler;
using System.Reflection;

namespace Billing
{
    public class ValidationScript
    {
        const string STD_USINGS = "using System; using System.Text; using System.Text.RegularExpressions; using System.Xml;";
        const string PREFIX = "namespace StandardBank.Shared.Validation.Instance {";
        const string METHOD = "public static object validate(object value, System.IO.TextWriter debug){";
        const string POSTFIX = "}}}";

        static public object runValidationScript(string script, object value, TextWriter debug)
        {
            object result = null;

            CSharpCodeProvider codeProvider = new CSharpCodeProvider();
            CompilerParameters parameters = new CompilerParameters();

            parameters.GenerateExecutable = false;
            parameters.GenerateInMemory = true;
            parameters.MainClass = null;
            parameters.IncludeDebugInformation = false;

            // Add available assemblies - this should be enough for the simplest
            // applications.
            //foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies())
            //{
            //    parameters.ReferencedAssemblies.Add(asm.Location);
            //    // Debug
            //    System.Diagnostics.Debug.Print(asm.Location);
            //}

            // Add available assemblies
            parameters.ReferencedAssemblies.Add("mscorlib.dll");
            parameters.ReferencedAssemblies.Add("system.dll");
            parameters.ReferencedAssemblies.Add("system.xml.dll");

            string code = STD_USINGS + PREFIX + METHOD + script + POSTFIX;

            // Debug
            //System.Diagnostics.Debug.Print(code);

            CompilerResults results = codeProvider.CompileAssemblyFromSource(parameters, code);

            if (results.Errors.Count > 0)
            {
                string errors = "Compilation failed:\n";
                foreach (CompilerError err in results.Errors)
                {
                    errors += err.ToString() + "\n";
                }

                // Debug
                //System.Diagnostics.Debug.Print(code);

                throw new ValidationScriptException(errors);

            }
            else
            {
                Assembly ass = results.CompiledAssembly;
                Type type = ass.GetType("StandardBank.Shared.Validation.Instance.ValidationInstance");

                MethodInfo method = type.GetMethod("validate");
                if (debug == null)
                {
                    debug = new StringWriter();
                }

                result = method.Invoke(Activator.CreateInstance(type), new Object[] { value, debug });
            }

            return result;

        }

    } // class ValidationScript


    public class ValidationScriptException : Exception
    {
        public ValidationScriptException(string str)
            : base(str)
        {
        }

        public ValidationScriptException(string str, Exception x)
            : base(str, x)
        {
        }

    }
}
